#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<hs/hs.h>

// 匹配状态数据结构
typedef struct status
{
    int flag; // 标志
    char ch;  // 当前匹配到的字符
    char *s;  // 原字符串
}status_t;

// 正则表达式编译及临时内存数据结构
typedef struct hs_db_scratch{
    hs_database_t *db;
    hs_scratch_t *scratch;
}hs_db_scratch_t;


// 排序比较函数
// 编译正则表达式并开辟临时内存
static int hs_prepare_scan(const char *pat, hs_db_scratch_t *p_ds);
// 匹配回调函数
static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx);
int cmp(const void *p, const void *q);
// 输出重复数字
void print_repetition(int n, hs_db_scratch_t *p_ds);

int main()
{
    int i;
    int a[] = {282112, 2822, 1234, 112355, 12345678};

    // 正则表达式(Hyperscan不支持\1这样的反向数字引用)
    const char *pat = "0{2,}|1{2,}|2{2,}|3{2,}|4{2,}|"
                      "5{2,}|6{2,}|7{2,}|8{2,}|9{2,}";
    hs_db_scratch_t ds = {0};
    // 编译正则表达式
    hs_prepare_scan(pat, &ds);

    for(i = 0; i < sizeof(a) / sizeof(a[0]); i++)
    {
        printf("%d: ", a[i]);
        print_repetition(a[i], &ds);
    }

    // 释放空间
    hs_free_database(ds.db);
    hs_free_scratch(ds.scratch);

    return 0;
}

static int hs_prepare_scan(const char *pat, hs_db_scratch_t *p_ds)
{
    hs_error_t error;
    hs_compile_error_t *compile_err;

    // 编译
    error = hs_compile(pat, HS_FLAG_DOTALL, HS_MODE_BLOCK, NULL,
                       &p_ds->db, &compile_err);
    if(error != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to compile pattern \"%s\": %s\n",
                pat, compile_err->message);
        hs_free_compile_error(compile_err);
        exit(EXIT_FAILURE);
    }

    error = hs_alloc_scratch(p_ds->db, &p_ds->scratch);
    if(error != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to allocate scratch space."
                        " Exiting.\n");
        hs_free_database(p_ds->db);
        exit(EXIT_FAILURE);
    }

    return 0;
}

// 输出重复数字
void print_repetition(int n, hs_db_scratch_t *p_ds)
{
    status_t st;
    // 数字字符串缓存
    char s[8] = {0};

    // 判断整数有效性
    if(n <= 0 || n > 10000000)
    {
        printf("Invalid input\n");
        return;
    }

    if(n > 0 && n < 10)
    {
        printf("No repeated numbers.\n");
        return;
    }

    // 将整数转换为字符串并排序
    sprintf(s, "%d", n);
    qsort(s, strlen(s), 1, cmp);

    st.flag = 0;
    st.ch = ' ';
    st.s = s;
    // 正则匹配
    if(hs_scan(p_ds->db, s, strlen(s), 0, p_ds->scratch, on_match, &st)
            != HS_SUCCESS)
    {
        fprintf(stderr, "ERROR: Unable to scan input buffer. Exiting.\n");
        hs_free_scratch(p_ds->scratch);
        hs_free_database(p_ds->db);
        exit(EXIT_FAILURE);
    }

    // 无重复数字
    if(!st.flag)
    {
        printf("No repeated numbers.\n");
    }
    else
    {
        printf("\n");
    }
}

int cmp(const void *p, const void *q)
{
    char ch_p = *((char*)p);
    char ch_q = *((char*)q);

    return (ch_p > ch_q) - (ch_p < ch_q);
}

static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx)
{
    status_t *tmp = (status_t *)ctx;

    tmp->flag = 1;
    if(tmp->s[to - 1] != tmp->ch)
    {
        tmp->ch = tmp->s[to - 1];
        putchar(tmp->ch);
        putchar(' ');
    }

    return 0; // 返回0继续匹配，返回1结束匹配
}
